function Lottery() {
    this.users = {              // 本期大乐透参与玩家
        /* uid: {               // 玩家UID
            name:'',            // 玩家名字
            headpic:'',         // 玩家头像
            server:0,           // 玩家所在服务器编号 config.ServerId
            nums:{              // 购买号码分布
                num : count,    // 购买的号码 : 注数
            },
        } */ 
    };            
                                
    this.openDay = 0;           // 本次开奖日期
    this.winNum = -1;           // 本期开奖号码, -1表示未开奖
    this.lastWinNum = -1;       // 保存上期号码,用于第二天显示上期号码
    this.pool = 0;              // 本次奖池
    this.lastPool = 0;          // 上期停止购买时奖池,用于第二天显示上期奖池奖金
    this.messages = {           // 超级奖中奖信息
        /* uid: {               // 中奖玩家UID
            name:'',            // 中奖玩家名字
            headpic:'',         // 中奖玩家头像
            server:0,           // 中奖玩家所在服务器编号 
            count:0,            // 中奖注数
        } */ 
    };         
                                
    this.serverMessagesMark = {};  // 服务器是否公告标志 eg: server:1
    this.onePrize = 0;          // 超级奖单注奖金
    this.updates = {};          // 更新
}

Lottery.create = function() {
    var lottery = {
        _id : 'lottery',
        user : {},
        open_day : 0,
        pool : 10000,
        last_pool : 0,
        win_num : -1,
        last_win_num : -1,
        message: {},
        one_prize: 0,
    };
    gDBWorld.insert(lottery, function(err,result){});
};

Lottery.prototype = {
    init : function(callback) {
        gDBWorld.findOne( { _id:'lottery'}, {}, function(err,doc){
            if( doc ) {
                this.users = doc.user;
                this.openDay = doc.open_day;
                this.pool = doc.pool;
                this.lastPool = doc.last_pool;
                this.winNum = doc.win_num;
                this.lastWinNum = doc.last_win_num;
                this.messages = doc.message;
                this.onePrize = doc.one_prize;
                callback && callback(true);
            }else {
                callback && callback(false); 
            } 
        }.bind(this));     
    },

    save : function(callback) {
        if( Object.keys(this.updates).length == 0 ) {
            callback && callback(true); 
            return;
        }  

        var updates = this.updates;
        gDBWorld.update({_id:'lottery'},{$set:updates},function(err,result){
            if( err ) {
                ERROR(err); 
                ERROR(updates);
                callback && callback(false);
            }else {
                callback && callback(true);
            } 
        });
        this.updates = {};
    },

    addUpdate : function(key, value) {
        this.updates[key] = value; 
    },

    addNumber : function(uid, name, headpic, server, num, count) {
        
        var user = this.getUser(uid);
        if( !user ) {
            user = {
                'name' : name, 
                'headpic' : headpic,
                'server' : server,
                'nums' : {},
            }; 

            this.users[uid] = user;
        }

        var nums = user.nums;
        if( !(num in nums) ) {
            nums[num] = 0; 
        }
        nums[num] += count;

        this.pool += count * gConfGlobal.LotteryOneCash;
        this.addUpdate('pool', this.pool);
        this.addUpdate(util.format('user.%d',uid), user);
    },

    getUser : function( uid ) {
        return this.users[uid] || null; 
    },

    isOpenPeriod : function() {
        var now = common.getTime(); 
        var todayDate = new Date();
        var todayStartTime = +(new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate(), 0, 0, 0)) / 1000;
        var todayEndTime = +(new Date(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate(), 23, 59, 59)) / 1000;
        var openStartTime = todayStartTime + gConfGlobal.LotteryOpenHour * 3600;
        return ( openStartTime <= now && now <= todayEndTime );
    },

    updateLotteryNumber : function() {
        var today = common.getDate();
        if( today != this.openDay ) {
            this.users = {};
            this.openDay = today;
            this.winNum = -1;
            this.pool = Math.max(this.pool, gConfGlobal.LotteryInitPool); 
            this.updates = {};

            this.addUpdate('user',{});
            this.addUpdate('open_day',today);
            this.addUpdate('win_num',this.winNum );
            if( this.lastPool != this.pool ) {
                this.addUpdate('pool',this.pool);
            }

            this.save();
        }

        if( !(this.isOpenPeriod()) || (this.winNum > 0) ) {
            return ; 
        }

        // 开奖
        this.lastPool = this.pool;
        this.onePrize = 0;
        if ( Object.keys(this.users).length <= 0 ) {
            // 没人买,随机不含0的 4位数作为开奖号码
            var randNum = 0;
            for( var i=1;i <= 4; ++i ) {
                randNum = randNum * 10 + common.randRange(1,9); 
            }

            this.winNum = this.lastWinNum = randNum ;
            this.messages = {};
            this.serverMessagesMark = {};

            this.addUpdate('message',this.messages);
            this.addUpdate('win_num',this.winNum);
            this.addUpdate('last_win_num',this.lastWinNum);
            this.addUpdate('last_pool',this.lastPool);
            this.addUpdate('one_prize',this.onePrize);

            return;
        }

        var selectNumber = {};
        var selectBlueNumber = {};
        var selectRedNumber = {};

        // 统计号码分布
        var users = this.users; 
        for( var uid in users ) {
            var nums = users[uid].nums; 

            for( var num in nums ) {
                var count = nums[num];
                var red = Math.floor( num / 10 );
                var blue = num % 10;
                if( !(num in selectNumber) ) {
                    selectNumber[num] = 0; 
                } 

                selectNumber[num] += count;
                if( !(red in selectRedNumber) ) {
                    selectRedNumber[red] = 0; 
                }

                selectRedNumber[red] += count;
                if( !(blue in selectBlueNumber) ) {
                    selectBlueNumber[blue] = 0;
                }

                selectBlueNumber[blue] += count; 
            }
        }

        var blueMin = 0;
        var redMin = 0;
        var winNum = 0;    // 开奖号码
        
        // 开奖
        var MINVALUE = 99999999;
        var minVal = MINVALUE;

        //计算蓝色球最少
        for( var blue in selectBlueNumber ) {
            var count = selectBlueNumber[blue]; 
            if( count < minVal ) {
                blueMin = +blue; 
                minVal = count;
            }
        }

        // 计算红色球最少 
        minVal = MINVALUE;
        for( var red in selectRedNumber ) {
            var count = selectRedNumber[red]; 
            if( count < minVal ) {
                redMin = +red; 
                minVal = count;
            }
        }

        var isSuperBought = false;    // 超级奖是否被购买
        var superOpenWeight = common.randRange(gConfGlobal.LotteryOpenMin, gConfGlobal.LotteryOpenMax);
        if( (gConfGlobal.LotteryOpenMin <= superOpenWeight) && (superOpenWeight <= gConfGlobal.LotteryOpenKey) ) {
            // 开超级奖
            //计算买的最少的号码
            minVal = MINVALUE;
            for( var num in selectNumber ) {
                var count = selectNumber[num]; 
                if( count < minVal ) {
                    winNum = +num; 
                    minVal = count;
                }
            }
              
            if( winNum in selectNumber ) {
                isSuperBought  = true;
            }
        }else {
            // 不开超级奖
            // 蓝色球必须9个号码都被买，才开幸运奖
            var allBlueBuy = true;      // 所有篮球是否被买
            if( Object.keys(selectBlueNumber).length != 9 ) {
                for( var i = 1; i <= 9; ++i ) {
                    if( !(i in selectBlueNumber) ) {
                        blueMin = i;
                        allBlueBuy = false;
                        break;
                    } 
                }
            }            

            // 找出没有被买过的号码
            var noOneBuyNums = [];
            for( var n = 1111; n < 9999; ++n ) {
                if( n.toString().indexOf('0') > 0 ) continue;
                
                if( !(n in selectNumber) ) {
                    noOneBuyNums.push(n);
                }
            }
            
            if( noOneBuyNums.length == 0 ) {
                // 所有号码都被买,开必须开超级奖
                winNum = redMin * 10 + blueMin; 
                isSuperBought = true;
            
            }else {
                // 开幸运奖
                if( !allBlueBuy ) {
                    winNum = common.randRange(1, 9) * 1000 + 
                        common.randRange(1, 9) * 100 + common.randRange(1, 9) * 10 + blueMin;
                }else {
                    for( var i = 0,len = noOneBuyNums.length; i < len; i++ ) {
                        if( (noOneBuyNums[i] % 10) == blueMin ) {
                           winNum = noOneBuyNums[i];  
                           break;
                        }
                    }

                    // 篮球注数最少的情况下,红球全被购买,选择红球注数最少的组合
                    if( !winNum ) {
                        winNum = redMin * 10 + blueMin; 
                        isSuperBought = true;
                    }
                } 
            }

        }
        
        this.winNum = this.lastWinNum = winNum;
        this.messages = {};
        this.serverMessagesMark = {};

        // 先将幸运奖从奖池中扣
        var blueNum = this.winNum % 10;
        var luckyCount = selectBlueNumber[blueNum];
        if( luckyCount ) {
            this.pool -= luckyCount * gConfGlobal.LotteryLuckyPrize; 
            if( this.pool < 0 ) this.pool = 0;

            this.lastPool = this.pool;
        }

        // 计算超级奖中奖信息
        if( isSuperBought ) {
            var totalCount = 0;
            var winNum = this.winNum;
            var messageArr = [];
            for( var uid in this.users ) {
                var user = this.users[uid]; 
                var nums = user.nums;
                if( winNum in nums ) {
                    var message = {
                        'uid' : +uid,
                        'name' : user['name'],
                        'headpic' : user['headpic'],
                        'server' : user['server'],
                        'count' : nums[winNum],
                    }; 

                    messageArr.push(message);
                    totalCount += nums[winNum];
                } 
            }

            if( totalCount ) {
                this.onePrize = Math.floor(this.lastPool / totalCount );
            }

            // 最多展示超级奖中奖玩家数量
            messageArr.sort(function(a,b) { return b.count - a.count; });

            var displayNum = Math.min( messageArr.length, gConfGlobal.LotteryDisplayMax );
            for( var i = 0, len = displayNum; i < len; ++i ) {
               var message = messageArr[i];  
               var uid = message.uid;
               delete message.uid;

               this.messages[uid] = message;
            }

            this.pool = 0;

        }

        this.addUpdate('message',this.messages);
        this.addUpdate('win_num',this.winNum);
        this.addUpdate('last_win_num',this.lastWinNum);
        this.addUpdate('pool',this.pool);
        this.addUpdate('last_pool',this.lastPool);
        this.addUpdate('one_prize',this.onePrize);
        this.save();
    },    

};

exports.get_lottery_number = function( req, res, resp ) {
    var uid = req.uid;
    do {
        gLottery.updateLotteryNumber();
        // 开奖后发送系统消息
        if( gLottery.winNum > 0 && Object.keys(gLottery.messages).length > 0 && 
            !(req.args.server in gLottery.serverMessagesMark) ) {

            var superInfos = {}; 
            for( var uid in gLottery.messages ) {
                var message = gLottery.messages[uid];
                superInfos[message.name] = message.count;
            }

            resp.data.super_infos = superInfos; 
            gLottery.serverMessagesMark[req.args.server] = 1;
        }

        resp.data.pool = gLottery.pool;
        resp.data.win_num = gLottery.winNum;
        resp.data.last_win_num = gLottery.lastWinNum;
        resp.data.my_nums = gLottery.getUser(uid) ? gLottery.getUser(uid).nums : {};
        resp.data.one_prize = gLottery.onePrize;
        resp.data.message = gLottery.messages;

    }while(false);

    gLottery.save();
    onReqHandled( res, resp );
};

exports.lottery_number_reward = function( req, res, resp ) {
    var uid = req.uid;
    do {
        gLottery.updateLotteryNumber();

        var user = gLottery.getUser(uid);
        if( !user ) {
            resp.code = 1; resp.desc = 'no lottery buy record'; break; 
        }

        if( !gLottery.isOpenPeriod() || gLottery.winNum < 0 ) {
            resp.code = 1; resp.desc = 'not in reward period'; break; 
        }

        var nums = user.nums;
        var prizeCash = 0;

        var onePrize = gLottery.onePrize;
        for(var num in nums) {
            var count = nums[num];
            if( +num == gLottery.winNum ) {
                // 超级奖
                prizeCash += Math.floor(onePrize * count * gConfGlobal.LotterySuperPrizeRate / 100);
            }else if( (num % 10) == (gLottery.winNum % 10) ) {
                // 幸运奖
                prizeCash += count * gConfGlobal.LotteryLuckyPrize; 
            }    
        }

        resp.data.prize_cash = prizeCash; 
    }while(false);

    gLottery.save();
    onReqHandled( res, resp );
};

exports.Lottery = Lottery;
